# coding: utf8


import copy


def test_shallow_copy():
    a = 100
    b = a
    a = 200
    print(
        " >>> a = 100           # 变量a引用对象100\n"
        " >>> b = a             # 将变量a赋值给变量b，等于建立变量b，其引用对象为a的引用对象\n"
        " >>> a = 200           # 改变a的引用对象\n"
        " >>> b                 # b的引用随之发生改变\n"
        f"{b}"
    )

    u = [1, 2, 3]
    v = u[:]
    v1 = u[:]
    v1[0] = 100
    u1 = [1, 2, [1, 2]]
    v2 = u1[:]
    v2[2][0] = 100

    print(
        "# 使用列表切片实现复制\n"
        " >>> u = [1, 2, 3]\n"
        " >>> v = u[:]              # 使用切片得到新的列表\n"
        " >>> v, id(v), id(u)       # 切片返回的是不同对象\n"
        f"{v, id(v), id(u)}\n"
        " >>> v[0] = 100            # 改变切片对象的元素\n"
        " >>> u, v                  # 没有影响到原列表的元素\n"
        f"{u, v1}\n"
        f" >>> u = [1, 2, [1, 2]]  # 使用切片复制一个多层列表\n"
        f" >>> v = u[:]\n"
        f" >>> v[2][0] = 100        # 试图改变副本的内层列表的值\n"
        f" >>> u, v                # 原列表也发生了变化，说明切片复制是浅复制！\n"
        f"{u1, v2}"
    )

    a = {'name': 'Wang', 'score': [100, 90, 85]}
    b = dict(a)
    v = a.values()
    k = list(a.keys())
    b['name'] = 'Li'
    b['score'][0] = 95
    print(
        " >>> a = {'name': 'Wang', 'score': [100, 90, 85]}\n"
        " >>> b = dict(a)               # 使用字典函数复制一个字典\n"
        " >>> b, id(b), id(a)           # 复制产生了新的对象\n"
        f"{b, id(b), id(a)}\n"
        f" >>> b['name'] = 'Li'         # 改变b中键'name'的值\n"
        f" >>> a, b                     # 只有b的值发生了变化\n"
        f"{a, b}\n"
        f" >>> b['score'][0] = 95       # 改变字典b的‘score’列表中的值\n"
        f" >>> a, b                     # 两个字典的值都发生了变化\n"
        f"{a, b}\n"
    )

    a = {'name': 'Wang', 'score': [100, 90, 85]}
    c = a.copy()
    print(
        " >>> a = {'name': 'Wang', 'score': [100, 90, 85]}\n"
        f" >>> c = a.copy()             # 通过copy方法，可以创建一个字典的副本\n"
        f" >>> c['name'] = 'Sun'        # 改变副本c的内容\n"
        f" >>> a, c                     # 没有影响到a的内容（第一层次！）\n"
        f"{a, c}\n")
    c['score'][0] = 300
    print(
        f" >>> c['score'][0] = 300      # 改变score的值，会影响到a的score的值\n"
        f" >>> c, a                     # copy方法是浅复制，没有对列表的元素进行复制\n"
        f"{c, a}\n"
    )

    # print(
        # f" >>> k = list(a.keys())       # 通过字典方法和list函数返回键列表对象, 但是键对象是原字典对象的引用\n"
        # f"{k}"
    # )
    # k[0] = 'first'
    # print(
    #     f" >>> k[0] = 'first'           # 改变键列表的值\n"
    #     f" >>> a                        # 原字典的键也发生了变化\n"
    #     f"{a}"
    # )


def test_deep_copy():
    import copy

    # shallow and deep copy examples
    x = [1, [2, [3, [4, 5]]]]
    y = copy.copy(x)
    y[1][1][1][0] = 1000
    z = copy.deepcopy(x)
    z[1][1][1][0] = 2000

    print(
        "# 浅层复制\n"
        " >>> x = [1, [2, [3, [4, 5]]]]     # 多次结构对象\n"
        " >>> y = copy.copy(x)              # 使用模块copy的浅复制方法copy进行复制\n"
        " >>> y[1][1][1][0] = 1000          # 改变列表y的深层结构中的内容\n"
        " >>> x                             # 列表x随之改变\n"
        f"{x}\n\n"
        f"# 实现深度复制\n"
        f" >>> z = copy.deepcopy(x)         # 对x进行深度复制\n"
        f" >>> z[1][1][1][0]= 2000          # 改变副本中的深层次对象值\n"
        f" >>> z\n"
        f"{z}\n"
        f" >>> x                            # 原列表对象没有改变\n"
        f"{x}"
    )

    # where do deepcopy occur
    class DemoClass5:
        pass

    s = ''.join([chr(90+i) for i in range(26)])
    t = tuple(range(10))
    tt = (1, (2, (3, (4, 5))))
    s1, t1, tt1 = copy.deepcopy(s), copy.deepcopy(t), copy.deepcopy(tt)


    print(
        "# 对于字符串、元组一类的不可变对象，深度复制方法只建立引用\n"
        " >>> s = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n"
        " >>> t = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)\n"
        " >>> tt = (1, (2, (3, (4, 5))))\n"
        " >>> s1, t1, tt1 = copy.deepcopy(s), copy.deepcopy(t), copy.deepcopy(tt)\n"
        " >>> id(s), id(s1)         # 字符串的深度复制没有建立新的对象\n"
        f"{id(s), id(s1)}\n"
        " >>> id(t), id(t1)         # 元组的深度复制没有建立新的对象\n"
        f"{id(t), id(t1)}\n"
        " >>> id(tt), id(tt1)       # 多层不可变对象的深度复制没有建立新的对象\n"
        f"{id(tt), id(tt1)}"
    )
